ConsultTopic Suggestions

Overview

The "ConsultTopic Suggestions" extension allows a Consultable to display a list of suggested topics the player can LOOK UP in it (just as the TOPICS command displays a list of suggested conversational topics). The commands HYPER SUGGS and ENUM SUGGS will affect the list of suggested ConsultTopics in the same way as for conversational topics (respectively hyperlinking and numbering the suggestions). To display a list of the suggested ConsultTopics associated with a given Consultable we need to call the Consultable's showSuggestions() method.

To implement this extension you need to include consultsugs.t (which you can find in the extentions folder under your adv3Lite folder) in your game, after the adv3Lite library files but before your other game files. You also need to create a number of ConsultTopic objects located in a one of more ConsultTopic object as described in the documentation for ConsultTopics. Both topicEntry.t and actor.t must be present among your library files (as they are by default). In addition you will need to define the name property on any ConsultTopic you wish to be suggested. This and the other modifications to the ConsultTopic and Consultable classes are explained in more detail below.

Enhancements to the ConsultTopic and Consultable Classes

This extensions adds the following properties to the ConsultTopic class which you can use to define how ConsultTopics are suggested:

Note that for a ConsultTopic to be suggested, its isActive property must also be true.

The extension adds the following method and property to the Consultable class:

Triggering Suggested ConsultTopics

The ConsultTopic Suggestions has no equivalent to a TOPICS command (or the Thought Suggestions THINK command) the player can use to generate a list of suggested ConsultTopics. Instead, game code needs to call the Consultable's showSuggestions command at some appropriate point in response to something else the player does, such as attempting to read the Consultable. The example below exhibits several of the possibilities:

blackBook: Consultable 'big black book' @startroom
    "It's a big black book called Vegetable Reference. "
    readDesc()
    {
        "It's a book in which you could look up a variety of topics. The index indicates that \v";;
        
        showSuggestions();
    }   
;

+ ConsultTopic @tCarrots
    "They're an orange root vegetable. "

    name = 'carrots'
;
    
+ ConsultTopic @tTomatoes
    "They're a round red fruit, but they're usually used as a vegetable. "
    
    name = 'tomatoes'
;

+ ConsultTopic @tWeather
    "The book supplies a wealth of too much information on the best kind of weather
    for growing various kinds of vegetable. "
    
    name = 'the weather'
    
    listOrder = 200
;

+ ConsultTopic @tIndex
    topicResponse()
    {
        "The index indicates that \v";
        location.showSuggestions();
    }   
;

+ DefaultConsultTopic
    topicResponse()
    {
        "The black book doesn't seem to have any information on that.<.p>";
        location.showSuggestions();
    }
;

+ Component 'index'
    desc()
    {
        "The index indicates that \v";
        location.showSuggestions();
    }
    
    readDesc = desc
;


tCarrots: Topic 'carrots';
tTomatoes: Topic 'tomatoes';
tIndex: Topic 'index';
tWeather: Topic 'weather';

Providing quite so many ways of triggering a list of ConsultTopics on the same Consultable may be overkill for many games. As game authors we can choose whichever of them we feel will best suit our game, or the particular Consultable within our game.

Using the customPrefix property

By default (in the English library) a list of suggested ConsultTopics will be introduced with 'You could look up '. This should work well enough for most Consultables, but we can tweak the wording if we want by defining a Consultable's customPrefix property to be something other than 'look up '. If we do so, however, our customPrefix string must observe the following rules:

  1. It must be supplied as a single-quoted string.
  2. It must be something that could immediately follow 'You could ' and immediatly precede the name of a suggested ConsultTopic.
  3. When combined with the name of a suggested ConsultTopic it must form a command that would work if the player entered it at the command prompt.

It follows that valid customPrefix strings will normally need to be one of the following:

In the final three examples we'd obviously need to substitute the name of the Consultable in question. To do this automatically, we can simply set the Consultable's useVerbosePrefix property to true, or override it to true on the Consultable class. For reasons why we might want to do so, see further below.

The reasons for these rules are (1) to ensure that players are prompted with commands that will work and (2) to ensure that hyperlinked and/or enumerated lists of suggested ConsultTopics work correctly.


Plurality Pitfalls

Everything we have described will work fine provided there's only ever one Consultable in scope at any one time. Having several in scope at once can potentially cause problems that adv3Lite does its best to mitigate but which game code may sometimes need to mititage further.

The first potential pitfall could arise from the use of 'look up' to introduce the list of suggested ConsultTopics, since presented with the command LOOK UP FOO, the parser has to decide what to look FOO up in. If there is only one Consultable in scope, that's not a problem, since the parser will simply pick that one Consultable. But if there are several, which one is the parser to pick? Adv3Lite tries to ensure that the parser picks the Consultable most recently read or consulted by the player character, and for the most part that probably works well enough. But if we find we're getting unwanted disambiguation prompts or other disamnbiguation problems, it may be better to resort to the more verbose form of the command for looking things up in things by including the following in our game:


modify Consultable
   useVerbosePrefix = true
;

This will result in suggested ConsultTopic lists like "You could consult the black book about carrots, tomatoes or the weather". The point here is not simply to prompt players to use the longer form of the command, but to make enumerated and/or hyperlinked suggestion lists do so (since what these lists do is simply replace the number typed or the hyperlink clicked by the player with the text of the suggestion, which is then parsed in the normal way). If the command is LOOK UP WEATHER, there may be some doubt what to look it up in (although the parser will do its best to guess intelligently), but if the command is CONSULT THE BLACK BOOK ABOUT THE WEATHER, all doubt is removed.

The second potential pitfall concerns the use of Compoments named 'index' as a means of generating a list of suggested ConsultTopics. That's fine if there's only one index in scope, but not so good if we have a stack of books each with its own index. In this case we not only need to give each index a unique name but also (ideally) help give the parser a nudge towards the right index if the player just types X INDEX or READ INDEX. We can achieve that by defining our index objects along the following lines:


+ Component 'black book index'
    desc()
    {
        "The index indicates that \v";
        location.showSuggestions();
    }
    
    readDesc = desc  
    
    /* Help the parser choose the index from the most recently referenced book */
    vocabLikelihood = location.currentConsultableScore
;

If we planned to have several books with indexes we could save ourselves quite a bit of typing by definiing a custom Index class:


class Index: Component 
    desc()
    {
        "\^<<theName> indicates that \v";
        location.showSuggestions();
    }
    
    readDesc = desc  
    
    /* Help the parser choose the index from the most recently referenced book */
    vocabLikelihood = location.currentConsultableScore
;

A third pitfall that could occur in the examples we gave above could be if we allowed READ to be used with multiple direct objects (e.g., READ BOOKS). Currently the adv3Lite library doesn't allow this, partly to avoid the pitfall we're about to describe, but also because it seems sensible to restrict actors to reading one thing at a time. Game code could, however, override this restriction by including the following:


modify VerbRule(Read)
    'read' multiDobj
    :
;

If we were to do that in our game, then READ BOOKS could produce quite a messy and confusing list of suggested ConsultTopics for a number of different books all at once if, as in the examples above, we'd used the readDesc property of those books to trigger a list of suggested ConsultTopics. Even worse, enumerated suggestions and possibly hyperlinked suggestions might not work as expected - despite being listed for all the books they'd only work properly for the last one.

The easiest way to avoid such pitfalls is to avoid changing VerbRule(Read) to allow multiple direct objects. If, however, there is some compelling reason why we need multiple objects to be read on the same turn, then we'll need to find some other way to avoid the mess that could result from a command like READ BOOKS applied to Consultables that use their readDesc properties to display lists of suggested topics to look up. The most obvious approach would be to use a CollectiveGroup, or, if (as is likely) the books are portable, MobileCollectiveGroup, along the lines of:


bookGroup: MobileCollectiveGroup 'books;;;them'
    collectiveActions = [Examine, Read]
    readDesc = "You can only read these books one at a time. "
;